package com.lehecai.ucenter.action.server;

import com.google.common.collect.Lists;
import com.lehecai.core.YesNoStatus;
import com.lehecai.core.exception.cache.CacheException;
import com.lehecai.core.service.cache.CacheService;
import com.lehecai.core.service.memcached.MemcachedService;
import com.lehecai.core.util.CharsetConstant;
import com.lehecai.core.util.CoreHttpUtils;
import com.lehecai.ucenter.action.BaseAction;
import com.lehecai.ucenter.entity.app.App;
import com.lehecai.ucenter.entity.permission.User;
import com.lehecai.ucenter.service.app.AppService;
import com.lehecai.ucenter.service.permission.UserService;
import com.lehecai.ucenter.utils.AuthorizeSignUtils;
import com.lehecai.ucenter.utils.AuthorizeTicketUtils;
import com.lehecai.ucenter.utils.GoogleAuthenticator;
import com.lehecai.ucenter.utils.MemcachedTicket;
import org.apache.commons.lang.StringUtils;
import org.apache.struts2.ServletActionContext;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SubmitAction extends BaseAction {
	
	private static final long serialVersionUID = -8634484692576627642L;
	
	private UserService userService;
    private CacheService cacheService;
    private String cacheName;
	
	private MemcachedService memcachedService;
	
	private String token;

    private Long uid;
	private String username;
	private String password;
	private String verifyCode;
    private String oneTimePassword;
	
	private String callback;//成功后回调地址
    private String appName;
    private AppService appService;
    private String sign;
    private String random;
	
	public String handle() {
		if (StringUtils.isEmpty(token)) {
			logger.error("授权登录参数不全！");
			super.setErrorMessage("授权登录参数不全！");
			return "authorizeFailure";
		}
        App tempApp = appService.findByToken(token);
        if (tempApp == null) {
            logger.error("您所访问系统未经过用户中心授权！");
            super.setErrorMessage("您所访问系统未经过用户中心授权！");
            return "authorizeFailure";
        }
        Map<String, String> paramsMap = new HashMap<String, String>();
        paramsMap.put("token", token);
        paramsMap.put("sign", sign);
        paramsMap.put("random", random);
        paramsMap.put("callback", callback);

		if (StringUtils.isEmpty(username)) {
			logger.error("用户名为空");
			super.setErrorMessage("用户名不能为空");
            appName = tempApp.getName();
            paramsMap.put("errMessage", "1");
            super.setForwardUrl(CoreHttpUtils.getQueryUrl("/authorize.do", paramsMap, CharsetConstant.CHARSET_UTF8));
            return "forward";
		}
		if (StringUtils.isEmpty(password)) {
			logger.error("密码为空");
			super.setErrorMessage("密码不能为空");
            appName = tempApp.getName();
            paramsMap.put("errMessage", "2");
            super.setForwardUrl(CoreHttpUtils.getQueryUrl("/authorize.do", paramsMap, CharsetConstant.CHARSET_UTF8));
            return "forward";
		}
		if (StringUtils.isEmpty(verifyCode)) {
			logger.error("验证码为空");
			super.setErrorMessage("验证码不能为空");
            appName = tempApp.getName();
            paramsMap.put("errMessage", "3");
            super.setForwardUrl(CoreHttpUtils.getQueryUrl("/authorize.do", paramsMap, CharsetConstant.CHARSET_UTF8));
            return "forward";
		}
        HttpServletRequest request = ServletActionContext.getRequest();
        String kaptchaExpected = (String)request.getSession()
                .getAttribute(com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY);
        if (verifyCode == null || !verifyCode.equalsIgnoreCase(kaptchaExpected)) {
            logger.error("验证码错误");
            super.setErrorMessage("验证码错误");
            appName = tempApp.getName();
            paramsMap.put("errMessage", "4");
            super.setForwardUrl(CoreHttpUtils.getQueryUrl("/authorize.do", paramsMap, CharsetConstant.CHARSET_UTF8));
            return "forward";
        }

		User user = userService.login(username, password);
		if (user == null) {
			logger.error("用户名或密码错误");
			super.setErrorMessage("用户名或密码错误");
            appName = tempApp.getName();
            paramsMap.put("errMessage", "5");
            super.setForwardUrl(CoreHttpUtils.getQueryUrl("/authorize.do", paramsMap, CharsetConstant.CHARSET_UTF8));
            return "forward";
		}
		if (tempApp.getOtpFlag().getValue() == YesNoStatus.YES.getValue() && user.getOtp().getValue() == YesNoStatus.NO.getValue()) {
			logger.error("该系统必须开启动态密码才能登录，请开启动态密码登录！");
			super.setErrorMessage("该系统必须开启动态密码才能登录，请开启动态密码登录！");
			return "authorizeFailure";
		}

        if (user.getOtp().getValue() == YesNoStatus.YES.getValue()) {
            logger.info("用户[{}]已开启动态密码验证", user.getUsername());
            uid = user.getId();
            return "oneTimePassword";
        }

		List<App> ownAppList = null;
		if (user != null) {
			ownAppList = userService.findAppsByUser(user);
		}
		if (ownAppList == null) {
			ownAppList = Lists.newArrayList();
		}
		App loginApp = null;
		for (App app : ownAppList) {
			if (app.getToken().equals(token)) {
				loginApp = app;
				break;
			}
		}
		if (loginApp == null) {
			logger.error("该用户未被授权访问子系统");
			super.setErrorMessage("该用户未被授权访问子系统");
			return "authorizeFailure";
		}

		String ticket = AuthorizeTicketUtils.generateAuthorizeTicket();
        Map<String, String> params = new HashMap<String, String>();
		params.put("token", token);
		params.put("uid", user.getId() + "");
		params.put("ticket", ticket);
		params.put("random", AuthorizeSignUtils.generateRandomParam());
		
		params.put("sign", AuthorizeSignUtils.generateAuthorizeSign(params, loginApp.getSecret()));
		
		MemcachedTicket memcachedTicket = new MemcachedTicket();
		memcachedTicket.setTicket(ticket);
		memcachedTicket.setUid(user.getId() + "");
		try {
			memcachedService.set(ticket, memcachedTicket, 60);
		} catch (Exception e) {
			logger.error("将ticket信息存入mc失败");
			logger.error(e.getMessage(), e);
		}
		logger.info(CoreHttpUtils.getQueryUrl(callback, params, CharsetConstant.CHARSET_UTF8));
		super.setForwardUrl(CoreHttpUtils.getQueryUrl(callback, params, CharsetConstant.CHARSET_UTF8));
		return "forward";
	}

    public String secondVerify() {
        if (StringUtils.isEmpty(token)) {
            logger.error("授权登录参数不全！");
            super.setErrorMessage("授权登录参数不全！");
            return "authorizeFailure";
        }

        App tempApp = appService.findByToken(token);
        if (tempApp == null) {
            logger.error("您所访问系统未经过用户中心授权！");
            super.setErrorMessage("您所访问系统未经过用户中心授权！");
            return "authorizeFailure";
        }
        Map<String, String> paramsMap = new HashMap<String, String>();
        paramsMap.put("token", token);
        paramsMap.put("sign", sign);
        paramsMap.put("random", random);
        paramsMap.put("callback", callback);
        if (uid == null || uid <= 0L) {
            logger.error("授权登录参数不全！");
            super.setErrorMessage("授权登录参数不全！");
            return "authorizeFailure";
        }

        User user = userService.get(uid);

        //验证动态密码
        String cachedOneTimePassword = null;
        try {
            cachedOneTimePassword = cacheService.getObject(String.class, cacheName, oneTimePassword);
        } catch (CacheException e) {
            logger.error("从缓存中读取动态密码出错, key={}", oneTimePassword);
            logger.error(e.getMessage(), e);
        }

        if (!StringUtils.isEmpty(cachedOneTimePassword)) {
            String msg = String.format("动态密码已被使用:username=%s, cachedOneTimePassword=%s", username, cachedOneTimePassword);
            logger.error(msg);
            super.setErrorMessage(msg);
            appName = tempApp.getName();
            paramsMap.put("errMessage", "6");
            super.setForwardUrl(CoreHttpUtils.getQueryUrl("/authorize.do", paramsMap, CharsetConstant.CHARSET_UTF8));
            return "forward";
        }

        long t = System.currentTimeMillis();
        GoogleAuthenticator ga = new GoogleAuthenticator();
        ga.setWindowSize(5);  //should give 5 * 30 seconds of grace...

        long code = 0L;
        try {
            code = Long.parseLong(oneTimePassword);
        } catch (NumberFormatException e) {
            String msg = String.format("动态密码格式不正确，转换成long错误:username=%s, password=%s", username, oneTimePassword);
            logger.error(msg);
            logger.error(e.getMessage(), e);
            super.setErrorMessage(msg);
            appName = tempApp.getName();
            paramsMap.put("errMessage", "7");
            super.setForwardUrl(CoreHttpUtils.getQueryUrl("/authorize.do", paramsMap, CharsetConstant.CHARSET_UTF8));
            return "forward";
        }

        boolean r = ga.check_code(user.getSecretKey(), code, t);
        if (!r) {
            String msg = String.format("动态密码不正确:username=%s, otp=%s", username, oneTimePassword);
            logger.error(msg);
            super.setErrorMessage(msg);
            appName = tempApp.getName();
            paramsMap.put("errMessage", "8");
            super.setForwardUrl(CoreHttpUtils.getQueryUrl("/authorize.do", paramsMap, CharsetConstant.CHARSET_UTF8));
            return "forward";
        }

        try {
            cacheService.setObject(cacheName, oneTimePassword, oneTimePassword);
        } catch (CacheException e) {
            logger.error("设置缓存出错, key={}", oneTimePassword);
            logger.error(e.getMessage(), e);
        }

        logger.info("用户身份认证通过！username={}", username);
        List<App> ownAppList = null;
        if (user != null) {
            ownAppList = userService.findAppsByUser(user);
        }
        if (ownAppList == null) {
            ownAppList = Lists.newArrayList();
        }
        App loginApp = null;
        for (App app : ownAppList) {
            if (app.getToken().equals(token)) {
                loginApp = app;
                break;
            }
        }
        if (loginApp == null) {
            logger.error("该用户未被授权访问子系统");
            super.setErrorMessage("该用户未被授权访问子系统");
            return "authorizeFailure";
        }
        String ticket = AuthorizeTicketUtils.generateAuthorizeTicket();
        Map<String, String> params = new HashMap<String, String>();
        params.put("token", token);
        params.put("uid", user.getId() + "");
        params.put("ticket", ticket);
        params.put("random", AuthorizeSignUtils.generateRandomParam());

        params.put("sign", AuthorizeSignUtils.generateAuthorizeSign(params, loginApp.getSecret()));

        MemcachedTicket memcachedTicket = new MemcachedTicket();
        memcachedTicket.setTicket(ticket);
        memcachedTicket.setUid(user.getId() + "");
        try {
            memcachedService.set(ticket, memcachedTicket, 60);
        } catch (Exception e) {
            logger.error("将ticket信息存入mc失败");
            logger.error(e.getMessage(), e);
        }
        logger.info(CoreHttpUtils.getQueryUrl(callback, params, CharsetConstant.CHARSET_UTF8));
        super.setForwardUrl(CoreHttpUtils.getQueryUrl(callback, params, CharsetConstant.CHARSET_UTF8));
        return "forward";
    }

	public UserService getUserService() {
		return userService;
	}

	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	public String getToken() {
		return token;
	}

	public void setToken(String token) {
		this.token = token;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getVerifyCode() {
		return verifyCode;
	}

	public void setVerifyCode(String verifyCode) {
		this.verifyCode = verifyCode;
	}

	public String getCallback() {
		return callback;
	}

	public void setCallback(String callback) {
		this.callback = callback;
	}

	public MemcachedService getMemcachedService() {
		return memcachedService;
	}

	public void setMemcachedService(MemcachedService memcachedService) {
		this.memcachedService = memcachedService;
	}

    public String getAppName() {
        return appName;
    }

    public void setAppName(String appName) {
        this.appName = appName;
    }

    public AppService getAppService() {
        return appService;
    }

    public void setAppService(AppService appService) {
        this.appService = appService;
    }

    public String getSign() {
        return sign;
    }

    public void setSign(String sign) {
        this.sign = sign;
    }

    public String getRandom() {
        return random;
    }

    public void setRandom(String random) {
        this.random = random;
    }

    public String getOneTimePassword() {
        return oneTimePassword;
    }

    public void setOneTimePassword(String oneTimePassword) {
        this.oneTimePassword = oneTimePassword;
    }

    public Long getUid() {
        return uid;
    }

    public void setUid(Long uid) {
        this.uid = uid;
    }

    public CacheService getCacheService() {
        return cacheService;
    }

    public void setCacheService(CacheService cacheService) {
        this.cacheService = cacheService;
    }

    public String getCacheName() {
        return cacheName;
    }

    public void setCacheName(String cacheName) {
        this.cacheName = cacheName;
    }
}
